#include "ml20dll.h"

int startremotevideo( INJDATA *injdata )
{
    HANDLE hProcess = injdata->msnt.rp;
    HINSTANCE    hkernel;
    HANDLE    remotethread;

    hkernel = GetModuleHandle( "kernel32" );

    injdata->FreeLibrary = (BOOL (__stdcall *)(HMODULE)) GetProcAddress( hkernel, "FreeLibrary" );
    injdata->LoadLibraryX = (HMODULE (__stdcall *)(LPCSTR)) GetProcAddress( hkernel, "LoadLibraryA" );
    injdata->GetProcAddress = (FARPROC (__stdcall *)(HMODULE, LPCSTR)) GetProcAddress( hkernel, "GetProcAddress" );

    //write startvideothread to injdata->remotecode
    injdata->remotecode = VirtualAllocEx( hProcess, 0, svt_size( ), MEM_COMMIT, PAGE_EXECUTE_READWRITE );
    if( !injdata->remotecode )
        return FALSE;
    if( !WriteProcessMemory( hProcess, injdata->remotecode, (void*) svt_address( ), svt_size( ), NULL ) )
        return FALSE;
    //write injdata to injdata->remotedata
    injdata->remotedata = VirtualAllocEx( hProcess, 0, sizeof(INJDATA), MEM_COMMIT, PAGE_READWRITE );
    if( !injdata->remotedata )
        return FALSE;
    if( !WriteProcessMemory( hProcess, injdata->remotedata, injdata, sizeof(INJDATA), NULL ) )
        return FALSE;

    //run it
    remotethread = CreateRemoteThread( hProcess, 0, 0, (LPTHREAD_START_ROUTINE) injdata->remotecode, injdata->remotedata, 0, NULL );
    if( !remotethread )
        return FALSE;

    WaitForSingleObject( remotethread, INFINITE );

    //read injdata back
    if( !ReadProcessMemory( hProcess, injdata->remotedata, injdata, sizeof(INJDATA), NULL ) )
        return FALSE;

    if( !VirtualFreeEx( hProcess, injdata->remotecode, 0, MEM_RELEASE ) )
        return FALSE;

    //get me some memory for output
    injdata->remoteout = VirtualAllocEx( hProcess, 0, injdata->BITM.biSizeImage, MEM_COMMIT, PAGE_READWRITE );
    if( !injdata->remoteout )
        return FALSE;

    //write decodevideothread to injdata->remotecode
    injdata->remotecode = VirtualAllocEx( hProcess, 0, dvt_size( ), MEM_COMMIT, PAGE_EXECUTE_READWRITE );
    if( !injdata->remotecode )
        return FALSE;
    if( !WriteProcessMemory( hProcess, injdata->remotecode, (void*) dvt_address( ), dvt_size( ), NULL ) )
        return FALSE;

    return TRUE;
}

int decoderemotevideo( INJDATA *injdata, uint8_t *data, int size )
{
    HANDLE    remotethread;
    HANDLE hProcess = injdata->msnt.rp;

    injdata->ML20.biSizeImage = size;

    //write in data to injdata->in
    injdata->in = VirtualAllocEx( hProcess, 0, size, MEM_COMMIT, PAGE_READWRITE );
    if( !injdata->in )
        return FALSE;
    if( !WriteProcessMemory( hProcess, injdata->in, data, size, NULL ) )
        return FALSE;

    //write injdata
    if( !WriteProcessMemory( hProcess, injdata->remotedata, injdata, sizeof(INJDATA), NULL ) )
        return FALSE;

    remotethread = CreateRemoteThread( hProcess, 0, 0, (LPTHREAD_START_ROUTINE) injdata->remotecode, injdata->remotedata, 0, NULL );
    if( !remotethread )
        return FALSE;
    WaitForSingleObject( remotethread, INFINITE );

    if( !ReadProcessMemory( hProcess, injdata->remoteout, injdata->out, injdata->BITM.biSizeImage, NULL ) )
        return FALSE;

    //read injdata back
    if( !ReadProcessMemory( hProcess, injdata->remotedata, injdata, sizeof(INJDATA), NULL ) )
        return FALSE;

    if( !VirtualFreeEx( hProcess, injdata->in, 0, MEM_RELEASE ) )
        return FALSE;

    return TRUE;
}

int endremotevideo( INJDATA *injdata )
{
    HANDLE remotethread;
    HANDLE hProcess = injdata->msnt.rp;

    if( !VirtualFreeEx( hProcess, injdata->remotecode, 0, MEM_RELEASE ) )
        return FALSE;

    injdata->remotecode = VirtualAllocEx( hProcess, 0, evt_size( ), MEM_COMMIT, PAGE_EXECUTE_READWRITE );
    if( !injdata->remotecode )
        return FALSE;
    if( !WriteProcessMemory( hProcess, injdata->remotecode, (void*) evt_address( ), evt_size( ), NULL ) )
        return FALSE;

    if( !WriteProcessMemory( hProcess, injdata->remotedata, injdata, sizeof(INJDATA), NULL ) )
        return FALSE;

    remotethread = CreateRemoteThread( hProcess, 0, 0, (LPTHREAD_START_ROUTINE) injdata->remotecode, injdata->remotedata, 0, NULL );
    if( !remotethread )
        return FALSE;
    if( !WaitForSingleObject( remotethread, INFINITE ) )
        return FALSE;

    if( !VirtualFreeEx( hProcess, injdata->remotecode, 0, MEM_RELEASE ) )
        return FALSE;
    if( !VirtualFreeEx( hProcess, injdata->remotedata, 0, MEM_RELEASE ) )
        return FALSE;

    return TRUE;
}
